﻿#include "FITKAbaqusAdaptorElement.h"
#include "InpKeyLineSpliter.h"
#include "FITKAbaqusINPReader.h"
#include "FITKAbaqusINPWriter.h"
#include "InpReadInformationMapper.h"
#include "FITK_Kernel/FITKCore/FITKEnumTransformer.hpp"
#include "FITK_Interface/FITKInterfaceStructural/FITKAbaMeshPartVTK.h"
#include "FITK_Interface/FITKInterfaceModel/FITKAbstractElement.h"
#include "FITK_Interface/FITKInterfaceModel/FITKElementHex.h"
#include "FITK_Interface/FITKInterfaceModel/FITKElementQuad.h"
#include "FITK_Interface/FITKInterfaceModel/FITKElementTet.h"
#include "FITK_Interface/FITKInterfaceModel/FITKElementTri.h"
#include "FITK_Interface/FITKInterfaceStructural/FITKAbaAssembly.h"
#include "FITK_Component/FITKAbaqusData/FITKAbaqusPart.h"
#include "FITK_Interface/FITKInterfaceModel/FITKAbstractAssInstance.h"
#include "FITK_Interface/FITKInterfaceStructural/FITKAbaWire.h"
#include <QDebug>
//命名空间
namespace IO
{
    QString FITKAbaqusAdaptorElement::getAdaptorClass()
    {
        return "IO::FITKAbaqusAdaptorElement";
    }

    bool FITKAbaqusAdaptorElement::adaptR()
    {
        _modelData = dynamic_cast<Interface::FITKAbstractModel*>(_dataObj);
        if (!_modelData || !_reader)return false;
        bool readOK = false;
        // 回退一行 处理关键字信息 确定单元类型
        _reader->backLine();
        QString line = _reader->readLine();
        if (!line.toLower().startsWith("*element")) return false;
        //关键字处理
        InpKeyLineSpliter s(line, _reader);
        QString seleType = s["type"].toUpper();
        //part下的
        if (_modelData->getAbsModelType() == Interface::FITKModelEnum::AbsModelType::AMTMIX)
        {
            //质量点/惯量
            if (seleType == "MASS" || seleType == "ROTARYI")
                readOK = this->readPartElementInertia();
            //弹簧
            else if (seleType == "SPRING2" || seleType == "SPRING1" || seleType == "SPRINGA" || seleType == "DASHPOT2" || seleType == "DASHPOTA" || seleType == "DASHPOT1")
                readOK = this->readPartElementSpringDashpot();
            //单元
            else
                readOK = this->readPartElement();
        }
        //assembly
        else if (_modelData->getAbsModelType() == Interface::FITKModelEnum::AbsModelType::Assembly)
        {
            //质量点/惯量
            if (seleType == "MASS" || seleType == "ROTARYI")
                readOK = this->readAssemblyElementInertia();
            //弹簧
            else if (seleType == "SPRING2" || seleType == "SPRING1" || seleType == "SPRINGA" || seleType == "DASHPOT2" || seleType == "DASHPOTA" || seleType == "DASHPOT1")
                readOK = this->readAssemblyElementSpringDashpot();
            //连接器的线
            else if (seleType == "CONN3D2")
                readOK = this->readAssemblyElementConnector();
        }
        return readOK;
    }

    void FITKAbaqusAdaptorElement::setWriteElementId(int* writeElementId)
    {
        _writeElementId = writeElementId;
    }

    bool FITKAbaqusAdaptorElement::adaptW()
    {
        _modelData = dynamic_cast<Interface::FITKAbstractModel*>(_dataObj);
        if (!_modelData || !_writer)return false;
        bool writeOK = false;
        if (_modelData->getAbsModelType() == Interface::FITKModelEnum::AbsModelType::AMTMIX)
            writeOK = this->writePartElement();
        return writeOK;
    }

    bool FITKAbaqusAdaptorElement::readPartElement()
    {
        //part
        AbaqusData::FITKAbaqusPart* partData = dynamic_cast<AbaqusData::FITKAbaqusPart*>(_modelData);
        if (!partData || !_reader)return false;
        Interface::FITKAbaMeshPartVTK* mesh = partData->getMesh();
        if (mesh == nullptr) return false;
        //回退一行 处理关键字信息 确定单元类型
        _reader->backLine();
        QString line = _reader->readLine();
        InpKeyLineSpliter s(line, _reader);
        QString seleType = s["type"];
        //确定解析的单元类型
        Core::FITKEnumTransfer<Interface::FITKAbaMeshPartVTK::AbaEleType> abaEleTypeTrafer;
        bool isValid = false;
        auto eleType = abaEleTypeTrafer.fromString(seleType, isValid);
        if (!isValid)
        {
            _reader->consoleMessage(3, QString("ele type not supported yet : %1").arg(seleType));
            return false;
        }
        //解析单元 代码段
        while (!_reader->atEnd())
        {
            line = _reader->readLine();
            if (line.isEmpty())continue;
            if (line.startsWith("*")) return true;
            //单独处理一个单元的数据 支持多行的点
            while (line.trimmed().back() == QChar(',')/* || !_reader->atEnd()*/)
            {
                QString tempLine = _reader->readLine();
                if (tempLine.startsWith("*"))
                {
                    _reader->backLine();
                    break;
                }
                line += tempLine;
            }
            QStringList sList = line.split(',');
            if (sList.size() < 1)
            {
                _reader->consoleMessage(3, QString("readElement error,element line count :%1.").arg(sList.size()));
                return false;
            }
            QList<int> sIDList;
            // 文件中单元的编号
            int eleID = sList[0].toInt();
            for (int i = 1; i < sList.size(); i++)
            {
                // 文件中单元的编号
                if (sList[i].isEmpty()) continue;
                int nodeID = sList[i].toInt();
                sIDList.append(nodeID);
            }
            if (!mesh->appendElement(eleType, eleID, sIDList))
            {
                _reader->consoleMessage(3, QString("ReadElement Error,Element NodeIDList Count Error, ElementID : %1.").arg(eleID));
                return false;
            }
            _reader->sendCurrentPercent();
        }
        //未正常结束
        return false;
    }

    bool FITKAbaqusAdaptorElement::writePartElement()
    {
        //part
        AbaqusData::FITKAbaqusPart* partData = dynamic_cast<AbaqusData::FITKAbaqusPart*>(_modelData);
        if (!partData || !_writer || !_writeElementId)return false;
        auto mesh = partData->getMesh();
        if (mesh == nullptr) return false;
        // 写出节点函数主体
        QTextStream* stream = _writer->getStream();
        int eleCount = mesh->getElementCount();
        if (eleCount < 1) return false;

        //获取最大id的长度+1 作为字符宽度
        int width = QString::number(mesh->getElementMaxID()).size() + 1;
        //确定解析的单元类型
        Core::FITKEnumTransfer<Interface::FITKAbaMeshPartVTK::AbaEleType> abaEleTypeTrafer;
        Interface::FITKAbaMeshPartVTK::AbaEleType writeT = Interface::FITKAbaMeshPartVTK::AbaEleType::AbaEleNone;
        bool isValid = false;

        for (int i = 0; i < eleCount; ++i)
        {
            //判断类型是否一致
            auto type = mesh->getAbaElementType(i);
            if (type != writeT)
            {
                auto eleTypeStr = abaEleTypeTrafer.toStrting(type, isValid);
                if (!isValid) return false;
                *stream << "*Element, type=" << eleTypeStr << endl;
                writeT = type;
            }

            auto ele = mesh->getElementAt(i);
            int nodeCount = ele->getNodeCount();

            *stream << _writer->int2String(ele->getEleID(), width);
            for (int k = 0; k < nodeCount; ++k)
            {

                int nodeID = ele->getNodeID(k);
                *stream << "," << _writer->int2String(nodeID, width);
            }
            *stream << endl;
            *_writeElementId = ele->getEleID();
        }
        return true;
    }

    bool FITKAbaqusAdaptorElement::readPartElementInertia()
    {
        AbaqusData::FITKAbaqusPart* partData = dynamic_cast<AbaqusData::FITKAbaqusPart*>(_modelData);
        if (!partData || !_reader)return false;
        int partId = partData->getDataObjectID();
        //回退一行 处理关键字信息
        _reader->backLine();
        QString line = _reader->readLine();
        //关键字处理
        InpKeyLineSpliter s(line, _reader);
        //获取elsetName, type
        QString type = s["type"].toUpper().trimmed();
        QString elsetName = s["elset"];
        //插入数据
        InpElementDataInfo* dataInfo = new InpElementDataInfo;
        dataInfo->_elementType = type;
        dataInfo->_elesetName = elsetName;
        dataInfo->_modelId = partId;
        //获取编号
        QList<int> idPartList;
        while (!_reader->atEnd())
        {
            QString line = _reader->readLine().trimmed();
            if (line.startsWith("*"))
                break;
            QStringList str = line.split(',');
            if (str.size() < 2)return false;
            if (str.size() > 2)
                _reader->consoleMessage(2, QString("Warning too many element nodes : File:%1, Line:%2").arg(__FILE__).arg(__LINE__));
            bool ok = false;
            int id = str.at(1).trimmed().toInt(&ok);
            if (!ok || id == 0)return false;
            if (idPartList.contains(id))
                _reader->consoleMessage(2, QString("Warning element has duplicate nodes : File:%1, Line:%2").arg(__FILE__).arg(__LINE__));
            else
            {
                //插入数据
                idPartList.append(id);
                QPair<int, int> point(partId, id);
                ElementPointInfo rowPoint;
                rowPoint._elementPointData.append(point);
                dataInfo->_elementMap.append(rowPoint);
            }
        }
        //获取映射
        InpReadInformationMapper* mapper = _reader->getReadInpInformationMapper();
        if (!mapper)return false;
        mapper->insertElementInfo(dataInfo);
        return true;
    }

    bool FITKAbaqusAdaptorElement::readAssemblyElementInertia()
    {
        Interface::FITKAbaAssembly* assemblyData = dynamic_cast<Interface::FITKAbaAssembly*>(_modelData);
        if (!assemblyData || !_reader)return false;
        //回退一行 处理关键字信息
        _reader->backLine();
        QString line = _reader->readLine();
        //关键字处理
        InpKeyLineSpliter s(line, _reader);
        //获取elsetName, type
        QString type = s["type"].toUpper().trimmed();
        QString elsetName = s["elset"];
        //获取编号
        InpElementDataInfo* dataInfo = new InpElementDataInfo;
        dataInfo->_elementType = type;
        dataInfo->_elesetName = elsetName;
        dataInfo->_modelId = assemblyData->getDataObjectID();
        QHash<int, QList<int>> idInstance_Hash;
        while (!_reader->atEnd())
        {
            int instanceId = assemblyData->getDataObjectID();
            QString line = _reader->readLine().trimmed();
            if (line.startsWith("*"))
                break;
            QStringList str = line.split(',');
            if (str.size() < 2)return false;
            if (str.size() > 2)
                _reader->consoleMessage(2, QString("Warning too many element nodes : File:%1, Line:%2").arg(__FILE__).arg(__LINE__));
            bool ok = false;
            QStringList nodeIdStr = str.at(1).trimmed().split('.');
            int id = 0;
            if (nodeIdStr.size() == 1)
                id = nodeIdStr.at(0).toInt(&ok);
            else if (nodeIdStr.size() == 2)
            {
                Interface::FITKAbstractAssInstance* instance = assemblyData->getDataByName(nodeIdStr.at(0));
                if (!instance)return false;
                instanceId = instance->getDataObjectID();
                id = nodeIdStr.at(1).toInt(&ok);
            }
            if (!ok || id == 0)return false;
            if (idInstance_Hash.contains(instanceId) && idInstance_Hash.value(instanceId).contains(id))
                _reader->consoleMessage(2, QString("Warning element has duplicate nodes : File:%1, Line:%2").arg(__FILE__).arg(__LINE__));
            else
            {
                idInstance_Hash[instanceId].append(id);
                QPair<int, int> point(instanceId, id);
                ElementPointInfo rowPoint;
                rowPoint._elementPointData.append(point);
                dataInfo->_elementMap.append(rowPoint);
            }
        }
        //获取映射
        InpReadInformationMapper* mapper = _reader->getReadInpInformationMapper();
        if (!mapper)return false;
        mapper->insertElementInfo(dataInfo);
        return true;
    }

    bool FITKAbaqusAdaptorElement::readPartElementSpringDashpot()
    {
        AbaqusData::FITKAbaqusPart* partData = dynamic_cast<AbaqusData::FITKAbaqusPart*>(_modelData);
        if (!partData || !_reader)return false;
        //回退一行 处理关键字信息
        _reader->backLine();
        QString line = _reader->readLine();
        //关键字处理
        InpKeyLineSpliter s(line, _reader);
        //获取elsetName, type
        QString type = s["type"].toUpper().trimmed();
        QString elsetName = s["elset"];
        //创建element映射所需数据
        InpElementDataInfo* dataInfo = new InpElementDataInfo;
        dataInfo->_elementType = type;
        dataInfo->_elesetName = elsetName;
        dataInfo->_modelId = partData->getDataObjectID();
        //获取编号
        while (!_reader->atEnd())
        {
            QString line = _reader->readLine().trimmed();
            if (line.startsWith("*"))
                break;
            QStringList str = line.split(',');
            if (str.size() < 3)return false;
            if (str.size() > 3)
                _reader->consoleMessage(2, QString("Warning too many element nodes : File:%1, Line:%2").arg(__FILE__).arg(__LINE__));
            bool ok = false;
            //创建一行数据接收器
            ElementPointInfo rowPoint;
            //获取点
            for (int i = 1; i < 3; ++i)
            {
                //获取节点数据
                int pointId = str.at(i).trimmed().toInt(&ok);
                //获取instanceid和pointId
                int instanceId = partData->getDataObjectID();
                if (!ok || pointId <= 0)return false;
                QPair<int, int> point(instanceId, pointId);
                rowPoint._elementPointData.append(point);
            }
            dataInfo->_elementMap.append(rowPoint);
        }
        //获取映射
        InpReadInformationMapper* mapper = _reader->getReadInpInformationMapper();
        if (!mapper)return false;
        //存入映射
        mapper->insertElementInfo(dataInfo);
        return true;
    }

    bool FITKAbaqusAdaptorElement::readAssemblyElementSpringDashpot()
    {
        Interface::FITKAbaAssembly* assemblyData = dynamic_cast<Interface::FITKAbaAssembly*>(_modelData);
        if (!assemblyData || !_reader)return false;
        //回退一行 处理关键字信息
        _reader->backLine();
        QString line = _reader->readLine();
        //关键字处理
        InpKeyLineSpliter s(line, _reader);
        //获取elsetName, type
        QString type = s["type"].toUpper().trimmed();
        QString elsetName = s["elset"];
        //创建element映射所需数据
        InpElementDataInfo* dataInfo = new InpElementDataInfo;
        dataInfo->_elementType = type;
        dataInfo->_elesetName = elsetName;
        dataInfo->_modelId = assemblyData->getDataObjectID();
        //获取编号
        while (!_reader->atEnd())
        {
            QString line = _reader->readLine().trimmed();
            if (line.startsWith("*"))
                break;
            QStringList str = line.split(',');
            if (str.size() < 3)return false;
            if (str.size() > 3)
                _reader->consoleMessage(2, QString("Warning too many element nodes : File:%1, Line:%2").arg(__FILE__).arg(__LINE__));
            bool ok = false;
            //创建一行数据接收器
            ElementPointInfo rowPoint;
            //获取点
            for (int i = 1; i < 3; ++i)
            {
                //获取节点数据
                QStringList nodeIdStr = str.at(i).trimmed().split('.');
                //获取instanceid和pointId
                int instanceId = assemblyData->getDataObjectID();
                int pointId = 0;
                if (nodeIdStr.size() == 1)
                    pointId = nodeIdStr.at(0).toInt(&ok);
                else if (nodeIdStr.size() == 2)
                {
                    Interface::FITKAbstractAssInstance* instance = assemblyData->getDataByName(nodeIdStr.at(0));
                    if (!instance)return false;
                    instanceId = instance->getDataObjectID();
                    pointId = nodeIdStr.at(1).toInt(&ok);
                }
                if (!ok || pointId == 0)return false;
                QPair<int, int> point(instanceId, pointId);
                rowPoint._elementPointData.append(point);
            }
            dataInfo->_elementMap.append(rowPoint);
        }
        //获取映射
        InpReadInformationMapper* mapper = _reader->getReadInpInformationMapper();
        if (!mapper)return false;
        //存入映射
        mapper->insertElementInfo(dataInfo);
        return true;
    }

    bool FITKAbaqusAdaptorElement::readAssemblyElementConnector()
    {
        Interface::FITKAbaAssembly* assemblyData = dynamic_cast<Interface::FITKAbaAssembly*>(_modelData);
        if (!assemblyData || !_reader)return false;
        //获取映射
        InpReadInformationMapper* mapper = _reader->getReadInpInformationMapper();
        if (!mapper)return false;
        //获取线管理器
        Interface::FITKAbaWireManager* wireManager = assemblyData->getWireManager();
        if (!wireManager)return false;
        QList<int> idList{};
        QList<QPair<int, int>> nodeList1{};
        QList<QPair<int, int>> nodeList2{};
        //获取编号
        while (!_reader->atEnd())
        {
            QString line = _reader->readLine().trimmed();
            if (line.startsWith("*"))
                break;
            QStringList str = line.split(',');
            if (str.size() < 3)return false;
            if (str.size() > 3)
                _reader->consoleMessage(2, QString("Warning too many element nodes : File:%1, Line:%2").arg(__FILE__).arg(__LINE__));
            bool ok = false;
            //获取编号
            int id = str.at(0).toInt(&ok);
            if (!ok)return false;
            QPair<int, int> node1;
            QPair<int, int> node2;
            //获取点
            for (int i = 1; i < 3; ++i)
            {
                //获取节点数据
                QStringList nodeIdStr = str.at(i).trimmed().split('.');
                //获取instanceid和pointId
                int instanceId = assemblyData->getDataObjectID();
                int pointId = 0;
                if (nodeIdStr.size() == 1)
                {
                    if (nodeIdStr.at(0).trimmed().isEmpty())
                        pointId = -1;
                    else
                        pointId = nodeIdStr.at(0).toInt(&ok);
                }
                else if (nodeIdStr.size() == 2)
                {
                    Interface::FITKAbstractAssInstance* instance = assemblyData->getDataByName(nodeIdStr.at(0));
                    if (!instance)return false;
                    instanceId = instance->getDataObjectID();
                    pointId = nodeIdStr.at(1).toInt(&ok);
                }
                if (!ok || pointId == 0)return false;
                if (i == 1)
                    node1 = QPair<int, int>(instanceId, pointId);
                else if (i == 2)
                    node2 = QPair<int, int>(instanceId, pointId);
            }
            nodeList1.append(node1);
            nodeList2.append(node2);
            idList.append(id);
        }
        if (nodeList1.size() != nodeList2.size() && nodeList2.size() != idList.size())return false;
        //创建线模型
        Interface::FITKAbaWire* wireData = new Interface::FITKAbaWire;
        QList<int>::iterator iterId = idList.begin();
        for (QList<QPair<int, int>>::iterator iterNode1 = nodeList1.begin(), iterNode2 = nodeList2.begin(); iterNode1 != nodeList1.end(); ++iterNode1, ++iterNode2, ++iterId)
        {
            int id = *iterId;
            //创建线单元
            Interface::FITKAbaAssEleCONN3D2* element = new Interface::FITKAbaAssEleCONN3D2;
            element->setNode1(iterNode1->first, iterNode1->second);
            element->setNode2(iterNode2->first, iterNode2->second);
            wireData->appendDataObj(element);
            mapper->insertElementConnect(id, element);
        }
        wireManager->appendDataObj(wireData);
        QString nameWire = wireManager->checkName("Wire-1");
        wireData->setDataObjectName(nameWire);
        return true;
    }
}